#ifndef VTKFUNCTIONS_HPP
#define VTKFUNCTIONS_HPP

#include "vtkConstants.hpp"
#include "exceptions.hpp"
#include "typeHelpers.hpp"
#include "tinyxml2.h"

#include <filesystem>

namespace hms::vtk
{

namespace xml = tinyxml2;
namespace fs = std::filesystem;

fs::path getBoundaryPath      ( const fs::path& caseDir );
fs::path getConstantFieldsPath( const fs::path& caseDir );
fs::path getSourceFieldsPath  ( const fs::path& caseDir );
fs::path getBindingFilePath(
	const fs::path& caseDir,
	const std::string& caseName
);

template<typename T>
std::string lineNum( const T* t );

std::string nodeString( const xml::XMLNode* );
std::string errorTrace( const xml::XMLNode* );


namespace internal {


template<typename T>
xml::XMLError readAttrVal(
	const xml::XMLElement* elem,
	const char* attribute,
	T&& val
);

std::string readAttrError( const xml::XMLElement* elem, const char* attribute );


} // end namespace internal

template<typename T>
T getAttributeValueWithDefault(
	const xml::XMLElement* elem,
	const char* attribute,
	T defaultVal
);

template<typename T>
T getAttributeValue(
	const xml::XMLElement* elem,
	const char* attribute
);

/* During import, the xml document is const, and during export it isn't.
 * However, its structure is the same. Therefore, some functions can be used 
 * both during import and export. To maintain const correctness, the const-ness
 * is transcribed from the function argument to the return type. */
template<typename T>
using maybe_const_XMLElement = transcribe_const_t<T, xml::XMLElement>;


template<typename T>
maybe_const_XMLElement<T>* getChildNodeByName(
	T* parent,
	const char* name
);

template<typename T, typename A>
maybe_const_XMLElement<T>* getChildNodeByAttributeValue(
	T* parent,
	const char* childName,
	const char* attributeName,
	A&& attributeValue
);


template<typename T>
maybe_const_XMLElement<T>* getVtkNode( T* doc );


template<typename MeshType, typename T>
maybe_const_XMLElement<T>* getMeshNode( T* vtkNode );

template<typename MeshType, typename T>
maybe_const_XMLElement<T>* getCellData( T* vtkNode );


template<typename T>
maybe_const_XMLElement<T>* getBoundaryNode( T* parent );


template<typename T>
maybe_const_XMLElement<T>* getBoundaryPatch(
	T* boundary, const std::string& patchName );


template<typename T>
maybe_const_XMLElement<T>* getBoundaryPatch(
	T* patches, const BoundaryPatch& patch
);


} // namespace hms::vtk

#include "vtkFunctions.tpp"

#endif